package exredis

// Redis客户端.
// Redis中文手册文档请参考：http://redisdoc.com/ ，Redis官方命令请参考：https://redis.io/commands

import (
	"fmt"
	"sync"
	"time"

	"github.com/gomodule/redigo/redis"
)

var MyRedis *Redis

func init() {
	MyRedis = New(Config{Host: "127.0.0.1", Port: 6379, Db: 0})
}

const (
	DEFAULT_POOL_MAX_IDLE      = 1
	DEFAULT_POOL_MAX_ACTIVE    = 10
	DEFAULT_POOL_IDLE_TIMEOUT  = 180 * time.Second
	DEFAULT_POOL_MAX_LIFE_TIME = 60 * time.Second
	RESULT_OK                  = "OK"
)

// Redis客户端
type Redis struct {
	pool *redis.Pool
}

// Redis服务端但节点连接配置信息
type Config struct {
	Host string // IP/域名
	Port int    // 端口
	Db   int    // db
	Pass string // 密码
}

// Redis链接池统计信息
type PoolStats struct {
	redis.PoolStats
}

// 并发安全池（读写锁）
type Pool struct {
	Data map[string]interface{}
	Lock *sync.RWMutex
}

func (p Pool) Get(k string) interface{} {
	p.Lock.RLock()
	defer p.Lock.RUnlock()
	return p.Data[k]
}

func (p Pool) Set(k string, v interface{}) {
	p.Lock.Lock()
	defer p.Lock.Unlock()
	p.Data[k] = v
}

// 连接池map
var pools = &Pool{Data: make(map[string]interface{}), Lock: new(sync.RWMutex)}

// 创建redis操作对象.
func New(config Config) *Redis {
	r := &Redis{}
	poolKey := fmt.Sprintf("%s:%d,%d", config.Host, config.Port, config.Db)
	if v := pools.Get(poolKey); v == nil {
		pool := &redis.Pool{
			MaxIdle:         DEFAULT_POOL_MAX_IDLE,
			MaxActive:       DEFAULT_POOL_MAX_ACTIVE,
			IdleTimeout:     DEFAULT_POOL_IDLE_TIMEOUT,
			MaxConnLifetime: DEFAULT_POOL_MAX_LIFE_TIME,
			Dial: func() (redis.Conn, error) {
				c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", config.Host, config.Port))
				if err != nil {
					return nil, err
				}
				if len(config.Pass) > 0 {
					if _, err := c.Do("AUTH", config.Pass); err != nil {
						return nil, err
					}
				}
				if _, err := c.Do("SELECT", config.Db); err != nil {
					return nil, err
				}
				return c, nil
			},
			// 用来测试连接是否可用
			TestOnBorrow: func(c redis.Conn, t time.Time) error {
				_, err := c.Do("PING")
				return err
			},
		}
		pools.Set(poolKey, pool)
		r.pool = pool
	} else {
		r.pool = v.(*redis.Pool)
	}
	return r
}

// 关闭redis管理对象，将会关闭底层的
func (r *Redis) Close() error {
	return r.pool.Close()
}

// 设置属性 - MaxIdle
func (r *Redis) SetMaxIdle(value int) {
	r.pool.MaxIdle = value
}

// 设置属性 - MaxActive
func (r *Redis) SetMaxActive(value int) {
	r.pool.MaxActive = value
}

// 设置属性 - IdleTimeout
func (r *Redis) SetIdleTimeout(value time.Duration) {
	r.pool.IdleTimeout = value
}

// 设置属性 - MaxConnLifetime
func (r *Redis) SetMaxConnLifetime(value time.Duration) {
	r.pool.MaxConnLifetime = value
}

// 获取当前连接池统计信息
func (r *Redis) Stats() *PoolStats {
	return &PoolStats{r.pool.Stats()}
}

// 执行同步命令 - Do
func (r *Redis) Do(command string, args ...interface{}) (interface{}, error) {
	conn := r.pool.Get()
	defer conn.Close()
	return conn.Do(command, args...)
}

// 执行异步命令 - Send
func (r *Redis) Send(command string, args ...interface{}) error {
	conn := r.pool.Get()
	defer conn.Close()
	return conn.Send(command, args...)
}

// 预处理key
func (r *Redis) PreDo(command string, args ...interface{}) (interface{}, error) {
	/*if len(r.keyPrefix) > 0 {
		args[0] = r.keyPrefix + ":" + args[0].(string)
	}*/
	return r.Do(command, args...)
}

// 是否空值错误
func IsNil(e error) bool {
	if redis.ErrNil == e {
		return true
	}
	return false
}

// 是否"OK"
func IsOK(s string, e error) (bool, error) {
	if s == RESULT_OK {
		return true, e
	}
	return false, e
}

func KeyFieldToInterface(key, field string, fields ...string) []interface{} {
	args := make([]interface{}, len(fields)+2)
	args = append(args, key)
	args = append(args, field)
	for _, v := range fields {
		args = append(args, v)
	}
	return args
}

func KeyFieldValueToInterface(key, field, value string, fields ...string) []interface{} {
	args := make([]interface{}, len(fields)+3)
	args = append(args, key)
	args = append(args, field)
	args = append(args, value)
	for _, v := range fields {
		args = append(args, v)
	}
	return args
}
